package com.xk857.simpleeffect.utils;

import static android.content.Context.MODE_PRIVATE;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import androidx.annotation.NonNull;

import com.google.gson.Gson;
import com.xk857.simpleeffect.R;
import com.xk857.simpleeffect.activity.LoginActivity;
import com.xk857.simpleeffect.domain.Result;
import com.xk857.simpleeffect.enums.RequestEnum;
import com.xuexiang.xui.utils.WidgetUtils;
import com.xuexiang.xui.widget.dialog.LoadingDialog;
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.function.Consumer;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class OkHttpUtils {

    private static OkHttpUtils instance;
    private final OkHttpClient client;

    private OkHttpUtils() {
        client = new OkHttpClient();
    }

    public static synchronized OkHttpUtils getInstance() {
        if (instance == null) {
            instance = new OkHttpUtils();
        }
        return instance;
    }

    public static final String BASE_URL = "https://api.elf.xk857.com";
    //    public static final String BASE_URL = "http://10.8.72.120:20000";
    static MediaType mediaType = MediaType.parse("application/json;charset=utf-8");

    /**
     * GET请求
     *
     * @param context     环境上下文
     * @param requestEnum 请求地址URL
     * @param type        GSON解析的数据类型
     * @param callback    回到函数
     * @param <T>         回调的类型
     */
    public <T> void get(Context context, RequestEnum requestEnum, Type type, boolean showLoading, Consumer<T> callback) {
        if (!isConnected(context)) {
            ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                    .iconRes(R.drawable.icon_error_24)
                    .title(R.string.error)
                    .content(R.string.network_error)
                    .positiveText(R.string.yes)
                    .show());
            return;
        }
        LoadingDialog dialog = WidgetUtils.getLoadingDialog(context);
        if (showLoading) {
            dialog.show();
        }
        Request request = new Request.Builder().header("token", getToken(context)).url(requestEnum.getUrl()).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                if (showLoading) {
                    dialog.dismiss();
                }
                e.printStackTrace();

                ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                        .iconRes(R.drawable.icon_error_24)
                        .title(R.string.error)
                        .content(R.string.network_error)
                        .positiveText(R.string.yes)
                        .show());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (showLoading) {
                    dialog.dismiss();
                }
                assert response.body() != null;
                String jsonStr = response.body().string();
                System.out.println("数据接收成功：" + jsonStr);
                Gson gson = new Gson();
                Result res = gson.fromJson(jsonStr, Result.class);
                if (res.getCode() != 20000) {
                    showMsg(context, res);
                } else {
                    Result<T> result = gson.fromJson(jsonStr, type);
                    System.out.println(result.getData());
                    callback.accept(result.getData());
                }
            }
        });
    }

    /**
     * 检查设备是否联网
     */
    private Boolean isConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }

    private String getToken(Context context) {
        SharedPreferences preferences = context.getSharedPreferences("userInfo", MODE_PRIVATE);
//        Log.i("TAG",preferences.getString("token", ""));
        return preferences.getString("token", "");
    }

    /**
     * GET请求
     *
     * @param context  环境上下文
     * @param url      请求地址URL
     * @param type     GSON解析的数据类型
     * @param callback 回到函数
     * @param <T>      回调的类型
     */
    public <T> void get(Context context, String url, Type type, boolean showLoading, Consumer<T> callback) {
        if (!isConnected(context)) {
            ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                    .iconRes(R.drawable.icon_error_24)
                    .title(R.string.error)
                    .content(R.string.network_error)
                    .positiveText(R.string.yes)
                    .show());
            return;
        }
        LoadingDialog dialog = WidgetUtils.getLoadingDialog(context);
        if (showLoading) {
            dialog.show();
        }
        Request request = new Request.Builder().header("token", getToken(context)).url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                if (showLoading) {
                    dialog.dismiss();
                }
                e.printStackTrace();
                ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                        .iconRes(R.drawable.icon_error_24)
                        .title(R.string.error)
                        .content(R.string.network_error)
                        .positiveText(R.string.yes)
                        .show());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (showLoading) {
                    dialog.dismiss();
                }
                String jsonStr = response.body().string();
                Gson gson = new Gson();
                Result res = gson.fromJson(jsonStr, Result.class);
                if (res.getCode() != 20000) {
                    showMsg(context, res);
                } else {
                    Result<T> result = gson.fromJson(jsonStr, type);
                    System.out.println(result.getData());
                    callback.accept(result.getData());
                }
            }
        });
    }

    /**
     * POST请求
     *
     * @param context     环境上下文
     * @param requestEnum URL
     * @param type        GSON解析的数据类型
     * @param params      传递过来的参数
     * @param callback    回调函数
     * @param <T>         回调的类型
     * @param <V>         传递过来参数的类型
     */
    public <T, V> void post(Context context, RequestEnum requestEnum, Type type, V params, boolean showLoading, Consumer<T> callback) {
        if (!isConnected(context)) {
            ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                    .iconRes(R.drawable.icon_error_24)
                    .title(R.string.error)
                    .content(R.string.network_error)
                    .positiveText(R.string.yes)
                    .show());
            return;
        }
        LoadingDialog dialog = WidgetUtils.getLoadingDialog(context);
        if (showLoading) {
            dialog.show();
        }

        Gson gson = new Gson();
        RequestBody requestBody = RequestBody.create(mediaType, gson.toJson(params));
        Request request = new Request.Builder().header("token", getToken(context)).post(requestBody).url(requestEnum.getUrl()).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                if (showLoading) {
                    dialog.dismiss();
                }
                e.printStackTrace();
                ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                        .iconRes(R.drawable.icon_error_24)
                        .title(R.string.error)
                        .content(R.string.network_error)
                        .positiveText(R.string.yes)
                        .show());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (showLoading) {
                    dialog.dismiss();
                }
                String jsonStr = response.body().string();
                Result res = gson.fromJson(jsonStr, Result.class);
                if (res.getCode() != 20000) {
                    showMsg(context, res);
                } else {
                    Result<T> result = gson.fromJson(jsonStr, type);
                    System.out.println(result.getData());
                    callback.accept(result.getData());
                }
            }
        });
    }


    public <T, V> void put(Context context, RequestEnum requestEnum, Type type, V params, boolean showLoading, Consumer<T> callback) {
        if (!isConnected(context)) {
            ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                    .iconRes(R.drawable.icon_error_24)
                    .title(R.string.error)
                    .content(R.string.network_error)
                    .positiveText(R.string.yes)
                    .show());
            return;
        }
        LoadingDialog dialog = WidgetUtils.getLoadingDialog(context);
        if (showLoading) {
            dialog.show();
        }

        Gson gson = new Gson();
        RequestBody requestBody = RequestBody.create(mediaType, gson.toJson(params));
        Request request = new Request.Builder().header("token", getToken(context)).put(requestBody).url(requestEnum.getUrl()).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                if (showLoading) {
                    dialog.dismiss();
                }
                e.printStackTrace();
                ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                        .iconRes(R.drawable.icon_error_24)
                        .title(R.string.error)
                        .content(R.string.network_error)
                        .positiveText(R.string.yes)
                        .show());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (showLoading) {
                    dialog.dismiss();
                }
                String jsonStr = response.body().string();
                Result res = gson.fromJson(jsonStr, Result.class);
                if (res.getCode() != 20000) {
                    showMsg(context, res);
                } else {
                    Result<T> result = gson.fromJson(jsonStr, type);
                    System.out.println(result.getData());
                    callback.accept(result.getData());
                }
            }
        });
    }

    public <T, V> void delete(Context context, String url, Type type, V params, boolean showLoading, Consumer<T> callback) {
        if (!isConnected(context)) {
            ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                    .iconRes(R.drawable.icon_error_24)
                    .title(R.string.error)
                    .content(R.string.network_error)
                    .positiveText(R.string.yes)
                    .show());
            return;
        }
        LoadingDialog dialog = WidgetUtils.getLoadingDialog(context);
        if (showLoading) {
            dialog.show();
        }

        Gson gson = new Gson();
        RequestBody requestBody = null;
        if (params != null) {
            requestBody = RequestBody.create(mediaType, gson.toJson(params));
        }
        Request request = new Request.Builder().header("token", getToken(context)).delete(requestBody).url(url).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                if (showLoading) {
                    dialog.dismiss();
                }
                e.printStackTrace();
                ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                        .iconRes(R.drawable.icon_error_24)
                        .title(R.string.error)
                        .content(R.string.network_error)
                        .positiveText(R.string.yes)
                        .show());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                if (showLoading) {
                    dialog.dismiss();
                }
                String jsonStr = response.body().string();
                Result res = gson.fromJson(jsonStr, Result.class);
                if (res.getCode() != 20000) {
                    showMsg(context, res);
                } else {
                    Result<T> result = gson.fromJson(jsonStr, type);
                    System.out.println(result.getData());
                    callback.accept(result.getData());
                }
            }
        });
    }

    /**
     * 显示后端传递过来的提示信息，如果未登录或登录过期，则跳转到登录界面
     */
    private void showMsg(Context context, Result res) {
        ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                .iconRes(R.drawable.icon_info)
                .title(R.string.info)
                .content(res.getMsg())
                .positiveText(R.string.yes)
                .onPositive((dialog, which) -> {
                    if (res.getCode().equals(41000)) {
                        // 登录过期跳转到登录界面
                        context.startActivity(new Intent(context, LoginActivity.class));
                    }
                }).show());
    }


    /**
     * 上传文件
     *
     * @param url      请求地址
     * @param file     待上传文件
     * @param callback 回调函数
     */
    public <T> void uploadFile(Context context, String url, Type type, File file, Consumer<T> callback) {
        if (!isConnected(context)) {
            ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                    .iconRes(R.drawable.icon_error_24)
                    .title(R.string.error)
                    .content(R.string.network_error)
                    .positiveText(R.string.yes)
                    .show());
            return;
        }
        LoadingDialog dialog = WidgetUtils.getLoadingDialog(context);
        dialog.show();

        RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file)).build();
        Request request = new Request.Builder().header("token", getToken(context)).url(url).post(requestBody).build();
        Call call = client.newCall(request);

        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                dialog.dismiss();
                e.printStackTrace();
                ((Activity) context).runOnUiThread(() -> new MaterialDialog.Builder(context)
                        .iconRes(R.drawable.icon_error_24)
                        .title(R.string.error)
                        .content(R.string.network_error)
                        .positiveText(R.string.yes)
                        .show());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                dialog.dismiss();
                String jsonStr = response.body().string();
                Gson gson = new Gson();
                Result res = gson.fromJson(jsonStr, Result.class);
                if (res.getCode() != 20000) {
                    showMsg(context, res);
                } else {
                    Result<T> result = gson.fromJson(jsonStr, type);
                    System.out.println(result.getData());
                    callback.accept(result.getData());
                }
            }
        });
    }

    /**
     * 上传文件
     */
    public <T> void uploadFile(Context context, RequestEnum urlEnum, Type type, File file, Consumer<T> callback) {
        this.uploadFile(context, urlEnum.getUrl(), type, file, callback);
    }


}
